package com.christina.engine.processing.model;

import com.christina.engine.decision.model.DecisionResult;
import com.christina.engine.intent.model.Intent;
import lombok.Getter;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 处理事件数据模型
 * 记录处理过程中发生的各种事件
 */
@Getter
public class ProcessingEvent {
    
    private final String eventId;
    private final ProcessingEventType type;
    private final Object source;
    private final Map<String, Object> eventData;
    private final LocalDateTime timestamp;
    private final String message;
    private final Throwable exception;
    
    private ProcessingEvent(Builder builder) {
        this.eventId = builder.eventId;
        this.type = builder.type;
        this.source = builder.source;
        this.eventData = new HashMap<>(builder.eventData);
        this.timestamp = builder.timestamp != null ? builder.timestamp : LocalDateTime.now();
        this.message = builder.message;
        this.exception = builder.exception;
    }
    
    // 自定义getter方法返回防御性拷贝
    public Map<String, Object> getEventData() { 
        return new HashMap<>(eventData); 
    }
    
    // 便利方法
    public <T> T getEventData(String key, Class<T> type) {
        Object value = eventData.get(key);
        if (value != null && type.isInstance(value)) {
            return type.cast(value);
        }
        return null;
    }
    
    public boolean hasEventData(String key) {
        return eventData.containsKey(key);
    }
    
    public boolean isErrorEvent() {
        return type == ProcessingEventType.ERROR_OCCURRED || 
               type == ProcessingEventType.EXCEPTION_THROWN ||
               exception != null;
    }
    
    // Builder模式
    public static class Builder {
        private String eventId;
        private ProcessingEventType type;
        private Object source;
        private Map<String, Object> eventData = new HashMap<>();
        private LocalDateTime timestamp;
        private String message;
        private Throwable exception;
        
        public Builder eventId(String eventId) {
            this.eventId = eventId;
            return this;
        }
        
        public Builder type(ProcessingEventType type) {
            this.type = type;
            return this;
        }
        
        public Builder source(Object source) {
            this.source = source;
            return this;
        }
        
        public Builder eventData(String key, Object value) {
            this.eventData.put(key, value);
            return this;
        }
        
        public Builder eventData(Map<String, Object> data) {
            this.eventData.putAll(data);
            return this;
        }
        
        public Builder timestamp(LocalDateTime timestamp) {
            this.timestamp = timestamp;
            return this;
        }
        
        public Builder message(String message) {
            this.message = message;
            return this;
        }
        
        public Builder exception(Throwable exception) {
            this.exception = exception;
            return this;
        }
        
        public ProcessingEvent build() {
            if (type == null) {
                throw new IllegalArgumentException("Event type cannot be null");
            }
            if (eventId == null) {
                this.eventId = java.util.UUID.randomUUID().toString();
            }
            return new ProcessingEvent(this);
        }
    }
    
    public static Builder builder() {
        return new Builder();
    }
    
    // 静态工厂方法 - 常用事件类型
    public static ProcessingEvent stateChanged(String newState) {
        return builder()
                .type(ProcessingEventType.STATE_CHANGED)
                .message("State changed to: " + newState)
                .eventData("newState", newState)
                .build();
    }
    
    public static ProcessingEvent intentRecognized(Intent intent) {
        return builder()
                .type(ProcessingEventType.INTENT_RECOGNIZED)
                .message("Intent recognized: " + (intent != null ? intent.getType() : "null"))
                .eventData("intent", intent)
                .source(intent)
                .build();
    }
    
    public static ProcessingEvent decisionMade(DecisionResult result) {
        return builder()
                .type(ProcessingEventType.DECISION_MADE)
                .message("Decision made: " + (result != null ? result.getTargetService() : "null"))
                .eventData("decisionResult", result)
                .source(result)
                .build();
    }
    
    public static ProcessingEvent errorOccurred(String message, Throwable exception) {
        return builder()
                .type(ProcessingEventType.ERROR_OCCURRED)
                .message(message)
                .exception(exception)
                .eventData("errorMessage", message)
                .build();
    }
    
    public static ProcessingEvent requestReceived(Object request) {
        return builder()
                .type(ProcessingEventType.REQUEST_RECEIVED)
                .message("Request received")
                .source(request)
                .eventData("request", request)
                .build();
    }
    
    public static ProcessingEvent serviceExecuted(String serviceType, Object result) {
        return builder()
                .type(ProcessingEventType.SERVICE_EXECUTED)
                .message("Service executed: " + serviceType)
                .eventData("serviceType", serviceType)
                .eventData("result", result)
                .build();
    }
    
    public static ProcessingEvent responseGenerated(Object response) {
        return builder()
                .type(ProcessingEventType.RESPONSE_GENERATED)
                .message("Response generated")
                .source(response)
                .eventData("response", response)
                .build();
    }
    
    public static ProcessingEvent performanceMetric(String metricName, Object value) {
        return builder()
                .type(ProcessingEventType.PERFORMANCE_METRIC_RECORDED)
                .message("Performance metric recorded: " + metricName)
                .eventData("metricName", metricName)
                .eventData("value", value)
                .build();
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ProcessingEvent that = (ProcessingEvent) o;
        return Objects.equals(eventId, that.eventId);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(eventId);
    }
    
    @Override
    public String toString() {
        return "ProcessingEvent{" +
                "eventId='" + eventId + '\'' +
                ", type=" + type +
                ", timestamp=" + timestamp +
                ", message='" + message + '\'' +
                ", hasException=" + (exception != null) +
                ", dataKeys=" + eventData.keySet() +
                '}';
    }
}